package org.tis.tools.senior.module.developer.service.impl;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.tis.tools.senior.module.core.config.SvnProperties;
import org.tis.tools.senior.module.developer.controller.request.DeliveryListSelectRequest;
import org.tis.tools.senior.module.developer.entity.*;
import org.tis.tools.senior.module.developer.entity.enums.CommitType;
import org.tis.tools.senior.module.developer.entity.enums.ConflictType;
import org.tis.tools.senior.module.developer.entity.enums.DeliveryListFromType;
import org.tis.tools.senior.module.developer.entity.enums.FileUpdateType;
import org.tis.tools.senior.module.developer.entity.vo.*;
import org.tis.tools.senior.module.developer.exception.DeveloperException;
import org.tis.tools.senior.module.developer.service.ISDeliveryListService;
import org.tis.tools.senior.module.developer.service.ISMergeReportListService;
import org.tis.tools.senior.module.developer.service.ISMergeReportService;
import org.tis.tools.senior.module.developer.service.ISSvnKitService;
import org.tis.tools.senior.module.developer.util.DeveloperUtils;
import org.tmatesoft.svn.core.*;
import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager;
import org.tmatesoft.svn.core.internal.io.dav.DAVRepositoryFactory;
import org.tmatesoft.svn.core.internal.io.fs.FSRepositoryFactory;
import org.tmatesoft.svn.core.internal.io.svn.SVNRepositoryFactoryImpl;
import org.tmatesoft.svn.core.internal.wc.DefaultSVNOptions;
import org.tmatesoft.svn.core.io.SVNRepository;
import org.tmatesoft.svn.core.io.SVNRepositoryFactory;
import org.tmatesoft.svn.core.wc.*;

import javax.annotation.PostConstruct;
import java.io.*;
import java.util.*;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;

import static org.tmatesoft.svn.core.wc.SVNStatusType.STATUS_NONE;

@Service
@Transactional(rollbackFor = Exception.class)
public class SSvnKitServiceImpl implements ISSvnKitService {

    @Autowired
    private SvnProperties svnProperties;

    private ISVNAuthenticationManager svnAuthenticationManager;

    private SVNClientManager svnClientManager;
    @Autowired
    private ISMergeReportService mergeReportService;
    @Autowired
    private ISMergeReportListService mergeReportListService;
    @Autowired
    private ISDeliveryListService deliveryListService;

    private Map<String, String> buildPackEos = new HashMap<>();


    /**
     * 获取svn的提交历史记录
     *
     * @return
     */
    @Override
    public List<SvnCommit> loadSvnHistory(String url, int startRevision) throws SVNException {

        List<SvnCommit> scList = new ArrayList<>();
        SVNRepository repository = SVNRepositoryFactory.create(SVNURL.parseURIEncoded(url));
        repository.setAuthenticationManager(this.svnAuthenticationManager);
        LinkedList logEntries = new LinkedList();
        repository.log(new String[]{""}, startRevision, -1, true, true,
                0, false, null, logEntry -> {
                    if (logEntry.getRevision() != -1) {
                        logEntries.add(logEntry);
                    }
                });
        for (Object logEntry1 : logEntries) {
            /*
             * gets a next SVNLogEntry
             */
            SVNLogEntry logEntry = (SVNLogEntry) logEntry1;

            SvnCommit svnCommit = new SvnCommit();
            svnCommit.setRevision((int) logEntry.getRevision());
            svnCommit.setAuthor(logEntry.getAuthor());
            svnCommit.setCommitDate(logEntry.getDate());
            svnCommit.setMessage(logEntry.getMessage());

            if (logEntry.getChangedPaths().size() > 0) {

                Set changedPathsSet = logEntry.getChangedPaths().keySet();

                for (Object aChangedPathsSet : changedPathsSet) {

                    SVNLogEntryPath entryPath = logEntry.getChangedPaths().get(aChangedPathsSet);

                    SvnPath svnPath = new SvnPath();

                    String type = svnPath.getType().toString();
                    svnPath.setPath(entryPath.getPath());
                    svnPath.setType(CommitType.what(type));
                    if (entryPath.getCopyPath() != null) {
                        svnPath.setCopyPath(entryPath.getCopyPath());
                        svnPath.setCopyRevision((int) entryPath.getCopyRevision());
                    }
                }
            }
            scList.add(svnCommit);
        }

        return scList;
    }

    @Override
    public int getLastRevision(String url) throws SVNException {
        return (int) getLastRevision(SVNURL.parseURIEncoded(url)).getCommittedRevision().getNumber();
    }

    @Override
    public List<SvnFile> getDiffStatus(String url, String startRevision) throws SVNException {
        SVNURL svnurl = SVNURL.parseURIEncoded(url);
        return doDiffStatus(svnurl, startRevision, true);
    }

    @Override
    public List<SvnFile> getDiffStatus(String url, String startRevision, boolean includeDir) throws SVNException {
        SVNURL svnurl = SVNURL.parseURIEncoded(url);
        return doDiffStatus(svnurl, startRevision, includeDir);
    }

    @Override
    public List<SvnFile> getBranchDiffStatus(String url, String startRevision) throws SVNException {
        List<SvnFile> list = new ArrayList<>();
        SVNRepository repository = SVNRepositoryFactory.create(SVNURL.parseURIEncoded(url));
        repository.setAuthenticationManager(this.svnAuthenticationManager);
        // 分支最新版本
        long branchLatestRevision = getLastRevision(url);
        if (branchLatestRevision <= Long.valueOf(startRevision)) {
            return list;
        }
        Collection entries = repository.getDir("", -1, null, (Collection) null);
        for (Object o : entries) {
            SVNDirEntry entry = (SVNDirEntry) o;
            if (entry.getKind() == SVNNodeKind.DIR) {
                // 如果当前工程最后变动版本小于此次查询的起始版本，说明没有任何变动
                if (entry.getRevision() <= Long.valueOf(startRevision)) {
                    continue;
                }
                SVNRepository svnRepository = SVNRepositoryFactory.create(entry.getURL());
                svnRepository.setAuthenticationManager(this.svnAuthenticationManager);
                // 获取当前工程第一次提交版本
                AtomicLong firstRevision = new AtomicLong(0L);
                svnRepository.log(new String[] {""}, 0, -1, false, true,
                        1, false, null, logEntry ->
                                firstRevision.set(logEntry.getRevision()));
                // 如果查询起始版本大于工程的第一次提交版本号,无需判断是否为新增工程
                if (Long.valueOf(startRevision) > firstRevision.get()) {
                    svnRepository.log(new String[] {""}, Long.valueOf(startRevision), branchLatestRevision,
                            false, true, 1, false, null, logEntry ->
                                list.addAll(doBranchDiffStatus(entry.getURL(),
                                        startRevision, null)));
                } else {
                    svnRepository.log(new String[]{""}, firstRevision.get(), branchLatestRevision,
                            true, true, 1, false, null, logEntry -> {
                                boolean isCopy = false;
                                if (logEntry.getChangedPaths().size() > 0) {
                                    Set<String> changedPathsSet = logEntry.getChangedPaths().keySet();
                                    for (String aChangedPathsSet : changedPathsSet) {
                                        SVNLogEntryPath p = logEntry.getChangedPaths().get(aChangedPathsSet);
                                        if (p.getCopyPath() != null) {
                                            isCopy = true;
                                            break;
                                        }
                                    }
                                    if (isCopy) {
                                        list.addAll(doBranchDiffStatus(entry.getURL(),
                                                Long.toString(logEntry.getRevision()), null));
                                    } else {
                                        list.addAll(doBranchDiffStatus(entry.getURL(),
                                                Long.toString(logEntry.getRevision() - 1), null));
                                    }
                                }
                            });
                }
            }
        }
        return list;
    }

    @Override
    public long doMkDir(String url, String commitMessage) throws SVNException {
        SVNURL svnurl = SVNURL.parseURIEncoded(url);
        SVNCommitInfo info = this.svnClientManager.getCommitClient().doMkDir(new SVNURL[]{svnurl}, commitMessage);
        return info.getNewRevision();
    }

    @Override
    public long doDelete(String url, String commitMessage) throws SVNException {
        SVNURL svnurl = SVNURL.parseURIEncoded(url);
        SVNCommitInfo info = this.svnClientManager.getCommitClient().doDelete(new SVNURL[]{svnurl}, commitMessage);
        return info.getNewRevision();
    }

    @Override
    public void doCopy(String[] sourceUrls, String destUrl, String commitMessage) throws SVNException {
        SVNCopyClient svnCopyClient = this.svnClientManager.getCopyClient();
        SVNCopySource[] copySources = new SVNCopySource[sourceUrls.length];
        for (int i = 0; i < sourceUrls.length; i++) {
            copySources[i] = new SVNCopySource(SVNRevision.HEAD, SVNRevision.HEAD, SVNURL.parseURIEncoded(sourceUrls[i]));
        }
        svnCopyClient.doCopy(copySources, SVNURL.parseURIEncoded(destUrl + "/"), false, false,
                false, commitMessage, null);

    }

    @Override
    public List<String> getDir(String url) throws SVNException {
        List<String> list = new ArrayList<>();
        SVNRepository repository = SVNRepositoryFactory.create(SVNURL.parseURIEncoded(url));
        repository.setAuthenticationManager(this.svnAuthenticationManager);
        Collection entries = repository.getDir("", -1, null, (Collection) null);
        for (Object o : entries) {
            SVNDirEntry entry = (SVNDirEntry) o;
            if (entry.getKind() == SVNNodeKind.DIR) {
                list.add(entry.getName());
            }
        }
        return list;
    }

    @PostConstruct
    private void svnAuthenticationManagerInit() {
        setupLibrary();
        this.svnAuthenticationManager = SVNWCUtil.createDefaultAuthenticationManager(
                svnProperties.getUsername(), svnProperties.getPassword().toCharArray()
        );
        this.svnClientManager = SVNClientManager.newInstance(SVNWCUtil.createDefaultOptions(true),
                this.svnAuthenticationManager);
    }


    private SVNInfo getLastRevision(SVNURL url) throws SVNException {
        DefaultSVNOptions defaultOptions = SVNWCUtil.createDefaultOptions(true);
        SVNWCClient svnwcClient = new SVNWCClient(svnAuthenticationManager, defaultOptions);
        return svnwcClient.doInfo(url, SVNRevision.HEAD, SVNRevision.HEAD);

    }

    private List<SvnFile> doBranchDiffStatus(SVNURL url, String startRevision, String filter) throws SVNException {
        List<SvnFile> files = new ArrayList<>();
        SVNRevision start = SVNRevision.create(Long.valueOf(startRevision));
        DefaultSVNOptions defaultOptions = SVNWCUtil.createDefaultOptions(true);
        SVNDiffClient svnDiffClient = new SVNDiffClient(svnAuthenticationManager, defaultOptions);
        SVNRepository repository = SVNRepositoryFactory.create(url);
        repository.setAuthenticationManager(svnAuthenticationManager);
        svnDiffClient.doDiffStatus(url, start, url, SVNRevision.HEAD, SVNDepth.INFINITY, false, diff -> {
            if (!diff.getModificationType().equals(STATUS_NONE)) {
                if (StringUtils.isBlank(filter) || diff.getURL().getPath().startsWith(filter)) {
                    SvnFile svnFile = new SvnFile();
                    svnFile.setPath(DeveloperUtils.getPathUTF(diff.getURL().toString()));
                    CommitType what = CommitType.what(diff.getModificationType().toString());
                    if (what != null) {
                        svnFile.setType(what);
                        svnFile.setNodeType(diff.getKind().toString());
                        files.add(svnFile);
                    }
                }
            }
        });
        return files;
    }

    private List<SvnFile> doDiffStatus(SVNURL svnurl, String startRevision, boolean includeDir) throws SVNException {
        List<SvnFile> files = new ArrayList<>();
        SVNRevision start = SVNRevision.create(Long.valueOf(startRevision));
        DefaultSVNOptions defaultOptions = SVNWCUtil.createDefaultOptions(true);
        SVNDiffClient svnDiffClient = new SVNDiffClient(svnAuthenticationManager, defaultOptions);
//        SVNDepth depth = includeDir ? SVNDepth.INFINITY : SVNDepth.FILES;
        svnDiffClient.doDiffStatus(svnurl, start, svnurl, SVNRevision.HEAD, SVNDepth.INFINITY, false, diff -> {
            SvnFile svnFile = new SvnFile();
            svnFile.setPath(DeveloperUtils.getPathUTF(diff.getURL().toString()));
            CommitType what = CommitType.what(diff.getModificationType().toString());
            if (what != null) {
                svnFile.setType(what);
                svnFile.setNodeType(diff.getKind().toString());
                files.add(svnFile);
            }
        });
        return files;
    }


    private static void setupLibrary() {

        DAVRepositoryFactory.setup();

        SVNRepositoryFactoryImpl.setup();

        FSRepositoryFactory.setup();
    }

    @Override
    public String getPatchDeploy(String fullPath, String branchFull) throws SVNException {

        String src = DeveloperUtils.getFullPathSrcString(fullPath, branchFull);
        String buildPack = "";
        if("src".equals(src)){
            //获取缓存中贮存的.eos文件
            String projectModule = buildPackEos.get(DeveloperUtils.getProjectBuildPack(fullPath,branchFull));
            if(StringUtils.isNotBlank(projectModule)){
                return projectModule;
            }
            File fileEos = new File(svnProperties.getEosAddress() +
                    DeveloperUtils.getProjectBuildPack(fullPath,branchFull)+"/.eos");

            if(!fileEos.exists()){
                //初始化支持svn://协议的库。 必须先执行此操作。
                System.setProperty("svnkit.http.methods", "Basic,Digest,NTLM");
                DAVRepositoryFactory.setup();
                //相关变量赋值
                SVNURL repositoryURL = null;
                try {
                    repositoryURL = SVNURL.parseURIEncoded(DeveloperUtils.getProjectEosPath(fullPath,branchFull));
                } catch (SVNException e) {
                    e.getMessage();
                }
                ISVNOptions options = SVNWCUtil.createDefaultOptions(true);

                //实例化客户端管理类
                svnClientManager = SVNClientManager.newInstance(
                        (DefaultSVNOptions) options, svnProperties.getUsername(), svnProperties.getPassword());
                //要把版本库的内容check out到的目录
                File wcDir = new File(svnProperties.getEosAddress() +
                        DeveloperUtils.getProjectBuildPack(fullPath,branchFull));
                if (!wcDir.exists()) {
                    //创建父目录文件
                    wcDir.mkdirs();
                }
                //通过客户端管理类获得updateClient类的实例。
                SVNUpdateClient updateClient = svnClientManager.getUpdateClient();
                updateClient.setIgnoreExternals(false);
                //从svn导出指定文件,返回工作副本的版本号。
                long workingVersion= updateClient.doExport(repositoryURL, wcDir, SVNRevision.HEAD, SVNRevision.HEAD,
                        ".eos",true, SVNDepth.INFINITY);
            }
            try {
                Properties properties = new Properties();
                // 使用ClassLoader加载properties配置文件生成对应的输入流
                BufferedReader in = new BufferedReader(new FileReader(fileEos));
                // 使用properties对象加载输入流
                properties.load(in);
                //获取key对应的value值
                buildPack= properties.getProperty("contribution.type");
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return buildPack;
    }

    @Override
    public MergeReportDetail beforehandMerge(SProfiles profiles, String profilesBranch, SWorkitem workitem,
                     String workitemBranch, SDelivery delivery, List<SDeliveryList> deliveryLists) throws SVNException {

        List<String> projectNames = new ArrayList<>();
        //获取所有代码的所在工程名称
        deliveryLists.stream().collect(Collectors.groupingBy(SDeliveryList::getPartOfProject))
                .forEach((p, l) -> {
                    projectNames.add(p);
                });
        setupLibrary();
        ISVNOptions options = SVNWCUtil.createDefaultOptions(true);
        //实例化客户端管理类
        SVNClientManager svnClientManager = SVNClientManager.newInstance(
                (DefaultSVNOptions) options, svnProperties.getUsername(), svnProperties.getPassword());

        SVNDiffClient diffClient = svnClientManager.getDiffClient();
        diffClient.setIgnoreExternals(false);
        List<MergeReportListDetail> mergeReportListDetails = new ArrayList<>();
        diffClient.setEventHandler(new ISVNEventHandler() {
            @Override
            public void handleEvent(SVNEvent svnEvent, double v){
                if (svnEvent.getContentsStatus().toString().equals(ConflictType.CONFLICT.getValue().toString()) ||
                            svnEvent.getAction().toString().equals(ConflictType.TREE_CONFLICT.getValue().toString())){
                    //报存此次合并冲突的的记录
                    MergeReportListDetail mergeReportListDetail  = new MergeReportListDetail();
                    mergeReportListDetail.setProjectCode(DeveloperUtils.getLocalFilePath(profilesBranch,
                            svnEvent.getFile().getPath()));
                    //循环所有的文件代码提交类型
                    mergeReportListDetail.setFileUpdateType(FileUpdateType.OTHER);
                    for (FileUpdateType fileUpdateType:FileUpdateType.values()){
                        //判断与合并记录是否相同
                        if (svnEvent.getAction().toString().equals(fileUpdateType.getValue().toString())){
                            mergeReportListDetail.setFileUpdateType(fileUpdateType);
                            break;
                        }
                    }
                    //判断是否有冲突
                    if(svnEvent.getContentsStatus().toString().equals(ConflictType.CONFLICT.getValue().toString())){
                        mergeReportListDetail.setConflictType(ConflictType.CONFLICT);
                    }else{
                        mergeReportListDetail.setConflictType(ConflictType.TREE_CONFLICT);
                    }

                    mergeReportListDetails.add(mergeReportListDetail);
                }

            }
            @Override
            public void checkCancelled() { }
        });
        //创建修改的SvnClient
        SVNUpdateClient updateClient = svnClientManager.getUpdateClient();
        updateClient.setIgnoreExternals(false);
        //获取需要合并之间的版本号
        List<SVNRevisionRange> revisionRanges = getMergeBetweenRevision(delivery, deliveryLists, workitemBranch);
        //循环需要合并的工程
        for (String projectName:projectNames){
            //工作项的开发分支+工程
            SVNURL fath = SVNURL.parseURIEncoded(workitemBranch + "/" + projectName);
            //获取环境名称
            String profilesName = DeveloperUtils.getProfilesName(profilesBranch);
            //本地代码路径+环境名称+工程名称
            File file = new File(svnProperties.getProfilesCodePath() + profilesName +"/"+ projectName);
            //判断环境代码目录是否存在
            if (!file.exists()){
                throw new DeveloperException("请先把环境为" + profilesName + "代码checkout下来再操作!");
            }else{
                //更新本地代码
                updateClient.doUpdate(file, SVNRevision.HEAD, SVNDepth.INFINITY, false, false);
            }
            //执行合并
            diffClient.doMerge(fath, SVNRevision.HEAD, revisionRanges, file, SVNDepth.INFINITY,
                    false,false,true,false);
        }
        if (mergeReportListDetails.size() > 0){
            //组织冲突报告
            MergeReportDetail mergeReportDetail = new MergeReportDetail();
            mergeReportDetail.setItemName(workitem.getItemName());
            mergeReportDetail.setOwner(workitem.getOwner());
            mergeReportDetail.setDevelopers(workitem.getDevelopers());
            mergeReportDetail.setProfilesName(profiles.getProfilesName());
            mergeReportDetail.setRealMerge(false);
            //循环有冲突的代码
            for (MergeReportListDetail mergeReportListDetail:mergeReportListDetails){
                //如果是树冲突，不做处理
                if (mergeReportListDetail.getConflictType().equals(ConflictType.TREE_CONFLICT)){
                    continue;
                }
                //获取冲突代码路径的文件名称
                String programName = DeveloperUtils.getProgramName(mergeReportListDetail.getProjectCode());
                //新增请求谁也在改接口的对象
                DeliveryListSelectRequest request = new DeliveryListSelectRequest();
                request.setFileName(programName);
                //调用谁也在改接口获取此冲突文件与其他那些文件有冲突
                List<FileUsedList> fileUsedLists = deliveryListService.selectListByFileName(request);
                //判断是否有其他工作项修改过此文件
                if (fileUsedLists != null){
                    List<WhoChangedConflictDetail> whoChangedConflictDetails = new ArrayList<>();
                    for (FileUsedList fileUsedListOne:fileUsedLists){
                        //循环所有与之冲突的代码文件组装返回格式
                        for (FileUsedList fileUsedTwo:fileUsedListOne.getList()){
                            WhoChangedConflictDetail whoChangedConflictDetail = new WhoChangedConflictDetail();
                            whoChangedConflictDetail.setOwner(fileUsedTwo.getOwner());
                            whoChangedConflictDetail.setDevelopers(fileUsedTwo.getDevelopers());
                            whoChangedConflictDetail.setFullPath(fileUsedTwo.getFullPath());
                            whoChangedConflictDetail.setGuidWorkitem(fileUsedTwo.getGuidWorkitem());
                            whoChangedConflictDetails.add(whoChangedConflictDetail);
                        }
                    }
                    mergeReportListDetail.setWhoChangedConflictDetails(whoChangedConflictDetails);
                }

            }
            //值为与之冲突的代码集合信息
            mergeReportDetail.setConflictReportDetails(mergeReportListDetails);
            return mergeReportDetail;
        }
        return null;
    }

    @Override
    public MergeReportDetail realMerge (SProfiles profiles, String profilesBranch, SWorkitem workitem, String workitemBranch,
                SDelivery delivery, List<SDeliveryList> deliveryLists) throws SVNException {
        //调用预合并再测试一遍
        MergeReportDetail mergeReportDetail = beforehandMerge(profiles, profilesBranch, workitem,
                                                                            workitemBranch, delivery, deliveryLists);
        //判断是否有异常报告，如果有直接返回
        if (mergeReportDetail != null){
            return mergeReportDetail;
        }
        //要合并的工程名
        List<String> projectNames = new ArrayList<>();
        //获取所有代码的所在工程名称
        deliveryLists.stream().collect(Collectors.groupingBy(SDeliveryList::getPartOfProject))
                .forEach((p, l) -> {
                    projectNames.add(p);
                });
        ISVNOptions options = SVNWCUtil.createDefaultOptions(true);
        //实例化客户端管理类
        SVNClientManager svnClientManager = SVNClientManager.newInstance(
                (DefaultSVNOptions) options, svnProperties.getUsername(), svnProperties.getPassword());
        //获取差异的Client
        SVNDiffClient diffClient = svnClientManager.getDiffClient();
        diffClient.setIgnoreExternals(false);
        List<MergeReportListDetail> mergeReportLists = new ArrayList<>();
        diffClient.setEventHandler(new ISVNEventHandler() {
            @Override
            public void handleEvent(SVNEvent svnEvent, double v){
                //获取此次合并的所有记录
                if (!svnEvent.getAction().toString().equals("merge_begin") && !svnEvent.getNodeKind().toString().equals("dir")){
                    MergeReportListDetail mergeReportList = new MergeReportListDetail();
                    mergeReportList.setProjectCode(svnEvent.getFile().getPath());
                    //循环所有的文件代码提交类型
                    mergeReportList.setFileUpdateType(FileUpdateType.OTHER);
                    for (FileUpdateType fileUpdateType:FileUpdateType.values()){
                        //判断与合并记录是否相同
                        if (svnEvent.getAction().toString().equals(fileUpdateType.getValue().toString())){
                            mergeReportList.setFileUpdateType(fileUpdateType);
                            break;
                        }
                    }
                    for (ConflictType conflictType :ConflictType.values()){
                        if (conflictType.getValue().toString().equals(svnEvent.getAction().toString())){
                            mergeReportList.setConflictType(conflictType);
                            break;
                        } else if (conflictType.getValue().toString().equals(svnEvent.getContentsStatus().toString())){
                            mergeReportList.setConflictType(conflictType);
                            break;
                        }
                    }
                    mergeReportLists.add(mergeReportList);
                }
            }
            @Override
            public void checkCancelled() { }
        });

        //创建修改的SvnClient
        SVNUpdateClient updateClient = svnClientManager.getUpdateClient();
        updateClient.setIgnoreExternals(false);
        //获取需要合并之间的版本号
        List<SVNRevisionRange> revisionRanges = getMergeBetweenRevision(delivery, deliveryLists, workitemBranch);
        //保存最后需要提交的工程
        File[] files = new File[projectNames.size()];
        //循环这次合并有几个工程
        for (int i = 0; i < projectNames.size(); i++){
            //工作项的开发分支+工程
            SVNURL fath = SVNURL.parseURIEncoded(workitemBranch + "/" + projectNames.get(i));
            //获取环境名称
            String profilesName = DeveloperUtils.getProfilesName(profilesBranch);
            //本地代码路径+环境名称+工程名称
            File file = new File(svnProperties.getProfilesCodePath() + profilesName + "/" + projectNames.get(i));
            if (!file.exists()){
                throw new DeveloperException("请先把环境为" + profilesName + "代码checkout下来再操作!");
            }else{
                //合并前先执行svn update
                updateClient.doUpdate(file, SVNRevision.HEAD, SVNDepth.INFINITY, false, false);
            }
            //执行合并
            diffClient.doMerge(fath, SVNRevision.HEAD, revisionRanges, file, SVNDepth.INFINITY,
                    false,false,false,false);
            files[i] = file;
        }
        /*//申请的代码保存的集合
        List<File> fileList = new ArrayList<>();
        //申请的代码提交类型为删除的保存集合
        List<File> deleteLists = new ArrayList<>();
        for (SDeliveryList deliveryList:deliveryLists){
            File file = new File(DeveloperUtils.svnUrlToLocalPath(svnProperties.getProfilesCodePath(), profilesBranch,
                    deliveryList.getFullPath(), workitemBranch));
            //判断此文件提交类型是否是删除
            if (deliveryList.getCommitType().equals(CommitType.DELETED)){
                //将提交类型为删除的申请代码路径转变为本地环境代码路径
                deleteLists.add(file);
            }
            //将申请代码的路径转变为本地代码路径
            fileList.add(file);
        }
        //将此次申请的代码转成map
        Map<String, File> fileMap = fileList.stream().collect(Collectors.toMap(File::getPath, p -> p));
        //保存此次合并多需要回退的代码,
        List<SMergeReportList> revertReportLists = new ArrayList<>();
        for (SMergeReportList mergeReportList:mergeReportLists){
            //合并的代码是否可以获取申请中的代码
            File file = fileMap.get(mergeReportList.getProjectCode());
            if (file == null){
                revertReportLists.add(mergeReportList);
            }
        }
        //删除这次合并多的代码
        mergeReportLists.removeAll(revertReportLists);
        if (deleteLists.size() > 0){
            for (File file:deleteLists){
                //将代码文件提交类型为删除的先使用svn删除
                svnClientManager.getWCClient().doDelete(file, true, false);
            }
        }
        //投放申请中要提交的文件
        File[] commitfiles = fileList.toArray(new File[fileList.size()]);*/
        // TODO 暂时commit整个目录，后续完善
        //操作svn commit提交合并过的所有工程(目录级提交)
        SVNCommitInfo svnCommitInfo = svnClientManager.getCommitClient().doCommit(files, true,
                "[artf42307]:" + workitem.getItemName(), null, null,
                true, true, SVNDepth.INFINITY);
        /*//合并多的，需要回退的代码
        File[] revertFile = new File[deleteReportLists.size()];
        for (int i = 0;0 < deleteReportLists.size(); i++){
            revertFile[i] = new File(deleteReportLists.get(i).getProjectCode());
        }
        svnClientManager.getWCClient().doRevert(revertFile,  SVNDepth.INFINITY, null);*/

        //组织冲突报告
        SMergeReport mergeReport = new SMergeReport();
        mergeReport.setGuidDelivery(delivery.getGuid());
        mergeReport.setItemName(workitem.getItemName());
        mergeReport.setOwner(workitem.getOwner());
        mergeReport.setDevelopers(workitem.getDevelopers());
        mergeReport.setProfilesName(profiles.getProfilesName());
        //新增冲突报告
        mergeReportService.insert(mergeReport);
        //组织返回报告格式
        MergeReportDetail sMergeReportDetail = new MergeReportDetail();
        BeanUtils.copyProperties(mergeReport, sMergeReportDetail);
        sMergeReportDetail.setRealMerge(true);
        sMergeReportDetail.setConflictReportDetails(null);
        if (mergeReportLists.size() > 0){
            //保存此次合并的记录
            List<SMergeReportList> sMergeReportLists = new ArrayList<>();
            for (MergeReportListDetail mergeReportList:mergeReportLists){
                mergeReportList.setWhoChangedConflictDetails(new ArrayList<>());
                //新增合并对象
                SMergeReportList sMergeReportList = new SMergeReportList();
                //将合并的记录copy到新增的合并对象信息中
                BeanUtils.copyProperties(mergeReportList, sMergeReportList);
                sMergeReportList.setGuidMergeReport(mergeReport.getGuid());
                sMergeReportList.setProjectCode(DeveloperUtils.getLocalFilePath(profilesBranch,
                        mergeReportList.getProjectCode()));
                sMergeReportLists.add(sMergeReportList);

            }
            //新增报告代码明细
            mergeReportListService.insertBatch(sMergeReportLists);
            //有合并记录返回合并记录
            sMergeReportDetail.setConflictReportDetails(mergeReportLists);
            return sMergeReportDetail;
        }
        return sMergeReportDetail;
    }

    @Override
    public void checkoutProfilesCode(String profilesBranch) throws SVNException {
        //获取环境名称
        String profilesName = DeveloperUtils.getProfilesName(profilesBranch);
        //获取本地代码文件
        File localFile = new File(svnProperties.getProfilesCodePath() + profilesName);
        if (localFile.exists()){
            throw new DeveloperException("服务器已有此环境代码!");
        }
        ISVNOptions options = SVNWCUtil.createDefaultOptions(true);
        //实例化客户端管理类
        SVNClientManager svnClientManager = SVNClientManager.newInstance(
                (DefaultSVNOptions) options, svnProperties.getUsername(), svnProperties.getPassword());
        //获取环境分支的svn地址
        SVNURL profilesPath = SVNURL.parseURIEncoded(profilesBranch);
        //执行checkout操作
        svnClientManager.getUpdateClient().doCheckout(profilesPath, localFile, SVNRevision.HEAD,
                                                SVNRevision.HEAD, SVNDepth.INFINITY, false);
        //代码下载完成执行cleanup
        svnClientManager.getWCClient().doCleanup(localFile);
    }

    /**
     *
     * @param beginRevision 合并的起始版本号
     * @param endRevision 合并的终止版本号
     * @param atomicLongs 拉工程或新增工程的版本号
     * @return
     */
    public List<SVNRevisionRange> getSVNRevisionRange(long beginRevision, long endRevision,  List<Long> atomicLongs) {
        //合并区间集合
        List<SVNRevisionRange> svnRevisionRanges = new ArrayList<>();
        //判断此次申请版本号区间是否有拉工程或新增工程操作
        if (atomicLongs.size() > 0){
            for (int i = 0; i < atomicLongs.size(); i++){
                //申请的起始版本大于拉工程或新增工程操作的版本，跳出本次循环
                if (atomicLongs.get(i) <= beginRevision){
                    continue;
                }
                //判断是否从0起始版本开始，如果是，那么把起始版本变更为第一次拉工程版本
                if (i == 0 || atomicLongs.size() == 1){
                    beginRevision = atomicLongs.get(0);
                    continue;
                }
                /**
                 * 每一个SVNRevisionRange都是一个合并区间，
                 *  如:第一个是13版本号，它是拉工程或者新增工程，13版本不合并，13 - 1，起始版本不变
                 */
                /*if (i == 0 && atomicLongs.get(i)-1 != beginRevision){
                    SVNRevisionRange revision = new SVNRevisionRange(SVNRevision.create(beginRevision),
                                                                        SVNRevision.create(atomicLongs.get(i)-1));
                    svnRevisionRanges.add(revision);
                }*/
                //两个拉工程或新增工程之间可能有提交记录，获取中间需要合并的版本号区间
                if (i != 0){
                    SVNRevisionRange revision = null;
                    //起始版本为0时，按拉工程版本+1合并，不为0时，按申请起始版本合并
                    if (beginRevision == 0){
                        revision = new SVNRevisionRange(SVNRevision.create(atomicLongs.get(i-1)),
                                SVNRevision.create(atomicLongs.get(i)-1));
                    }else{
                        revision = new SVNRevisionRange(SVNRevision.create(beginRevision),
                                SVNRevision.create(atomicLongs.get(i)-1));
                    }
                    svnRevisionRanges.add(revision);
                }
                if (i == atomicLongs.size() - 1){
                    //最后的拉工程或新增工程的版本号与申请end的版本建立一个合并区间
                    SVNRevisionRange revision = new SVNRevisionRange(SVNRevision.create(atomicLongs.get(i)),
                                                                    SVNRevision.create(endRevision));
                    svnRevisionRanges.add(revision);
                }

            }
        }
        if (svnRevisionRanges.size() == 0){
            SVNRevisionRange revisionRange = new SVNRevisionRange(SVNRevision.create(beginRevision), SVNRevision.create(endRevision));
            svnRevisionRanges.add(revisionRange);
        }
        return svnRevisionRanges;
    }

    /**
     * 获取此分支新增工程或拉工程的的版本号
     * @param workitemBranch
     * @param beginVersion
     * @return
     * @throws SVNException
     */
    public List<Long> getAddProjectRevision(String workitemBranch, long beginVersion) throws SVNException {
        //一个版本号会有多个工程的拉取，去除重复项
        Set<Long> atomicLongs = new HashSet<>();
        //创建svn的库
        SVNRepository repository = SVNRepositoryFactory.create(SVNURL.parseURIEncoded(workitemBranch));
        //设置用户名和密码
        repository.setAuthenticationManager(this.svnAuthenticationManager);
        Collection entries = repository.getDir("", -1, null, (Collection) null);
        for (Object o : entries) {
            SVNDirEntry entry = (SVNDirEntry) o;
            // 如果当前工程最后变动版本小于此次查询的起始版本，说明没有任何变动
            if (entry.getRevision() <= Long.valueOf(beginVersion)) {
                continue;
            }
            if (entry.getKind() == SVNNodeKind.DIR) {
                SVNRepository svnRepository = SVNRepositoryFactory.create(entry.getURL());
                svnRepository.setAuthenticationManager(this.svnAuthenticationManager);
                // 获取当前工程第一次提交版本
                AtomicLong firstRevision = new AtomicLong(0L);
                svnRepository.log(new String[]{""}, 0, -1, false, true,
                        1, false, null, logEntry ->
                                firstRevision.set(logEntry.getRevision()));
                atomicLongs.add(firstRevision.get());
            }
        }
        //将set转为list
        List<Long> atomicLongList = new ArrayList<>(atomicLongs);
        //从小到大排序
        Collections.sort(atomicLongList);
        return atomicLongList;
    }

    /**
     * 获取需要合并之间的版本号
     */
    public List<SVNRevisionRange> getMergeBetweenRevision(SDelivery delivery, List<SDeliveryList> deliveryLists, String workitemBranch) throws SVNException {
        //筛选出从标准清单来源的代码
        List<SDeliveryList> sDeliveryLists = deliveryLists.stream().filter(sDeliveryList ->
                DeliveryListFromType.STANDARD.equals(sDeliveryList.getFromType())).collect(Collectors.toList());
        //合并之间的版本号
        List<SVNRevisionRange> revisionRanges = null;
        //判断此申请是否有来源于标准清单的代码
        if (sDeliveryLists.size() > 0){
            //获取此分支新增工程或拉工程的的版本号
            List<Long> atomicLongList = getAddProjectRevision(workitemBranch, 0);
            //有标准清单代码，等于是投放的新环境，把分支所有的修改内容都合并到环境上
            revisionRanges = getSVNRevisionRange(0 , delivery.getEndVersion(), atomicLongList);
        }else {
            //获取此分支新增工程或拉工程的的版本号
            List<Long> atomicLongList = getAddProjectRevision(workitemBranch, delivery.getBeginVersion());
            //申请的起始和结束版本号
            revisionRanges = getSVNRevisionRange(delivery.getBeginVersion(), delivery.getEndVersion(), atomicLongList);
        }
        return revisionRanges;
    }

}
